package com.aizhixin.lab.docker.service;

import com.aizhixin.lab.account.dto.AccountDTO;
import com.aizhixin.lab.config.Config;
import com.aizhixin.lab.docker.common.ExceptionValidation;
import com.aizhixin.lab.docker.core.ContainerConfig;
import com.aizhixin.lab.docker.domain.*;
import com.aizhixin.lab.docker.entity.ContainerToImages;
import com.aizhixin.lab.docker.entity.ImageInfo;
import com.aizhixin.lab.docker.entity.LastOperation;
import com.aizhixin.lab.docker.repository.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class DockerContainerService {
    @Autowired
    private Config config;
    @Autowired
    private ChapterContainerRepositroy chapterContainerRepositroy;
    @Autowired
    private DockerContainerService dockerContainerService;
    @Autowired
    private ContainerToImagesRepository containerToImagesRepository;
    @Autowired
    private LastOperationRepository lastOperationRepository;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private IoUtils ioUtils;
    @Autowired
    private DockerImageService dockerImageService;
    @Autowired
    private ChapterImagesRepository chapterImagesRepository;
    @Autowired
    private LastOperationService lastOperationService;
    @Autowired
    private ContainerToImagesService containerToImagesService;
    @Autowired
    private ImageInfoRepository imageInfoRepository;
    /**
     * 创建容器
     *
     * @param domain
     * @param token
     * @return
     */
    public FormData allocate(ContainerDomain domain, String token) throws InterruptedException {
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = new HashMap<>();
        map.put("imageName", domain.getImageName());
        map.put("count", domain.getCount());
        map.put("expire", domain.getExpire());
        map.put("owner", domain.getOwner());
        map.put("spec",domain.getSpec());
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/allocate";
        ResponseEntity<String> formDataResponseEntity = restTemplate.exchange(queryPath, HttpMethod.POST,request, String.class);
        FormData formData = JSON.parseObject(formDataResponseEntity.getBody(), FormData.class);
       return formData;
    }
    public void allocateByVersion(ContainerDomain domain,Long stuId, String token) {
        List<ContainerToImages> containerToImages = containerToImagesRepository.findByCourseIdAndChapterIdAndUserId(domain.getCourseId(), domain.getChapterId(), stuId);
        String version;
        if (containerToImages.size()>0){
            for (ContainerToImages c:containerToImages){
                domain.setImageName(c.getImagesName());
                version=c.getImageVersion();
                newContainer(domain,version,token);
            }
        }else {
            List<LastOperation> lastOperation = lastOperationRepository.findByCourseIdAndUserId(domain.getCourseId(), stuId);
            for (LastOperation l:lastOperation){
                domain.setImageName(l.getImagesName());
                version=l.getImagesVersion();
                newContainer(domain,version,token);
            }
        }

    }
    public void projectAllocateByVersion(ContainerDomain domain,Long stuId, String token) {
        List<ContainerToImages> containerToImages = containerToImagesRepository.findByCourseIdAndUserId(domain.getCourseId(), stuId);
        String version;
        if (containerToImages.size()>0){
            for (ContainerToImages c:containerToImages){
                domain.setImageName(c.getImagesName());
                version=c.getImageVersion();
                newContainer(domain,version,token);
            }
        }else {
            List<LastOperation> lastOperation = lastOperationRepository.findByCourseIdAndUserId(domain.getCourseId(), stuId);
            for (LastOperation l:lastOperation){
                domain.setImageName(l.getImagesName());
                version=l.getImagesVersion();
                newContainer(domain,version,token);
            }
        }

    }
    public void newContainer(ContainerDomain domain,String version, String token){
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = new HashMap<>();
        map.put("imageName", domain.getImageName());
        map.put("count", 1);
        map.put("expire", domain.getExpire());
        map.put("owner", domain.getOwner());
        map.put("imageVersion",version);
        map.put("spec",domain.getSpec());
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/allocate";
        ResponseEntity<String> formDataResponseEntity = restTemplate.postForEntity(queryPath, request, String.class);
        FormData formData = JSON.parseObject(formDataResponseEntity.getBody(), FormData.class);
    }
    /**
     * 删除容器
     *
     * @param containerName
     * @param token
     * @return
     */
    public FormData deleteContainer(String containerName, String token) {
        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        Map<String, Object> map = new HashMap<>();
        map.put("containerName", containerName);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/delete";
        ResponseEntity<String> responseEntity = restTemplate.exchange(queryPath, HttpMethod.DELETE, request, String.class);
        FormData formData = JSON.parseObject(responseEntity.getBody(), FormData.class);
        return formData;
    }

    /**
     * 设置默认规格
     * @param defaultSpecs
     * @param overSold
     * @param token
     * @return
     */
    public FormData setConfig(Integer defaultSpecs, Integer overSold, String token) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        Map<String, Object> map = new HashMap<>();
        map.put("defaultSpecs", defaultSpecs);
        map.put("overSold", overSold);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/config";
        ResponseEntity<String> responseEntity = restTemplate.exchange(queryPath, HttpMethod.PUT, request, String.class);
        FormData formData = JSON.parseObject(responseEntity.getBody(), FormData.class);
        return formData;
    }

    /**
     * 获取默认规格
     * @param token
     * @return
     */
    public FormData getConfig(String token) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        Map<String, Object> map = new HashMap<>();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/Config";
        ResponseEntity<String> responseEntity = restTemplate.exchange(queryPath, HttpMethod.GET, request, String.class);
        FormData formData = JSON.parseObject(responseEntity.getBody(), FormData.class);
        return formData;
    }
    /**
     * 获取容器列表
     * @param owner
     * @param
     * @param token
     * @return
     */
    public FormData getContainerList(String owner, String token){
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        Map<String, Object> map = new HashMap<>();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/list";
        queryPath+="?&owner="+owner;
        ResponseEntity<String> responseEntity = restTemplate.exchange(queryPath, HttpMethod.GET, request, String.class);
        FormData formData = JSON.parseObject(responseEntity.getBody(), FormData.class);
        return formData;
    }
    public FormData getContainerListByImages(String imageName, String token){
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        Map<String, Object> map = new HashMap<>();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/list";
        queryPath+="?&imageName="+imageName;
        ResponseEntity<String> responseEntity = restTemplate.exchange(queryPath, HttpMethod.GET, request, String.class);
        FormData formData = JSON.parseObject(responseEntity.getBody(), FormData.class);
        return formData;
    }
    public Integer deleteContainerToImage(String courseId,Long chapterId,Long stuId){
        int i = containerToImagesRepository.deleteByCourseIdAndChapterIdAndUserId(courseId, chapterId, stuId);
        return i;
    }
    public Integer deleteContainerToImage(String courseId,Long stuId){
        int i = containerToImagesRepository.deleteByCourseIdAndUserId(courseId, stuId);
        return i;
    }
    public Integer order(ArrayList<Image> imageArrayList,String userName,Integer size){
        List<String> collect = imageArrayList.stream().map(Image::getName).collect(Collectors.toList());
        boolean contains = collect.contains(userName + "image" + size);
        if (contains){
            return order(imageArrayList,userName,size+1);
        }else {
            return size;
        }
    }
    public boolean nameIsUse(ArrayList<Image> imageArrayList,String imageName){
        List<String> collect = imageArrayList.stream().map(Image::getName).collect(Collectors.toList());
        return collect.contains(imageName);

    }

    /**
     * 保存容器(管理端)
     * @param
     * @param token
     * @return
     */
    public Boolean rootSave(ContainerDomainV2 domainV2, AccountDTO dto, String token) {
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = new HashMap<>();
        map.put("containerIp", domainV2.getContainerIp());
        FormData<ArrayList<Image>> me = dockerImageService.getImageList(token, "me",dto.getId());
        if (nameIsUse(me.getData(),domainV2.getNewImageName())){
            return false;
        }
        map.put("imageName",domainV2.getNewImageName());
        map.put("imageDesc", "describe image"+domainV2.getNewImageName());
        map.put("creator", "me");
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/save";
        ResponseEntity<String> formDataResponseEntity = restTemplate.exchange(queryPath, HttpMethod.PUT, request, String.class);
        FormData formData = JSON.parseObject(formDataResponseEntity.getBody(), FormData.class);
        if (formData.getErrno()==-1){
            throw new ExceptionValidation(416, formData.getErrmsg());
        }
        VersionInfoDomain versionInfoDomain = JSON.parseObject(formData.getData().toString(), VersionInfoDomain.class);
        ImageInfo info = new ImageInfo();
        info.setImagesName(domainV2.getNewImageName());
        info.setImageDesc("describe image"+domainV2.getNewImageName());
        info.setCreateBy(dto.getId());
        imageInfoRepository.save(info);
        return true;
    }

    /**
     * 学生保存镜像
     * @param domainV2
     * @param dto
     * @param token
     * @return
     */
    public String save(ContainerDomainV2 domainV2, AccountDTO dto, String token) {
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> map = new HashMap<>();
        map.put("containerIp", domainV2.getContainerIp());
        map.put("imageName", dto.getUserName()+domainV2.getContainerName());
        map.put("imageDesc", "describe image"+dto.getUserName());
        map.put("creator", dto.getUserName());
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/container/save";
        ResponseEntity<String> formDataResponseEntity = restTemplate.exchange(queryPath, HttpMethod.PUT, request, String.class);
        FormData formData = JSON.parseObject(formDataResponseEntity.getBody(), FormData.class);
        if (formData.getErrno()==-1){
            throw new ExceptionValidation(416, formData.getErrmsg());
        }
        VersionInfoDomain versionInfoDomain = JSON.parseObject(formData.getData().toString(), VersionInfoDomain.class);

        return versionInfoDomain.getImageVersion();
    }

    /**
     * 镜像保存到数据库
     * @param domainV2
     * @param dto
     * @param version
     */
    public void saveImages(ContainerDomainV2 domainV2,AccountDTO dto,String version){
        ContainerToImages containerToImages = new ContainerToImages();
//        int i = containerToImagesRepository.deleteByCourseIdAndChapterIdAndUserId(domainV2.getCourseId(), domainV2.getChapterId(), dto.getId());

        containerToImages.setId(UUID.randomUUID().toString());
        containerToImages.setCourseId(domainV2.getCourseId());
        containerToImages.setChapterId(domainV2.getChapterId());
        containerToImages.setUserId(dto.getId());
        containerToImages.setImagesName(dto.getUserName()+domainV2.getContainerName());
        containerToImages.setImageVersion(version);
        containerToImages.setCreateDate(new Date());
        containerToImages.setIsAuto(false);
        containerToImagesRepository.save(containerToImages);
    }
    /**
     * 延迟保存容器
     * @param
     * @param accountDTO
     * @param token
     */
    public void deferSaveContainer(ContainerDomain containerDomain, AccountDTO accountDTO, String token,Long expire,String token1){
//        new Thread(new ContainerToImage(dockerContainerService, containerToImagesRepository, containerDomainV2, accountDTO, token,lastOperationRepository,expire)).start();
        new Thread(new AutoSaveImage(dockerContainerService, containerToImagesService, containerDomain, accountDTO, token,lastOperationService,expire,token1,redisTemplate)).start();
    }
    /**
     * 判断章节下是否有正在运行的容器
     * @param
     * @param name
     * @return
     */
    public Boolean getUserContainer(String courseId,Long chapterId,String name){
        Set<String> keys = redisTemplate.keys(name +":"+ chapterId + ":"+"*");
        if (keys.size()>0) {
            return true;
        }
        return false;
    }
    public Boolean getUserContainer(String projectId,String name){
        Set<String> keys = redisTemplate.keys(name +"|"+ projectId+"*");
        if (keys.size()>0) {
            return true;
        }
        return false;
    }
    public List<ContainerToImages> getUpExperiment(ContainerInfoDomainV3 domainV3, Long stuId){
        List<ContainerToImages> containerToImages = containerToImagesRepository.findByCourseIdAndChapterIdAndUserId(domainV3.getCourseId(), domainV3.getChapterId(), stuId);
        return containerToImages;
    }
    public List<ContainerToImages> getProjectUpExperiment(ContainerInfoDomainV3 domainV3, Long stuId){
        List<ContainerToImages> containerToImages = containerToImagesRepository.findByCourseIdAndUserId(domainV3.getProjectId(), stuId);
        return containerToImages;
    }
    public List<LastOperation> getLastOperation(String courseId,Long studId){
        List<LastOperation> lastOperation = lastOperationRepository.findByCourseIdAndUserId(courseId, studId);
        return lastOperation;
    }
    public FormData getResourceList(String token){
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("token", token);
        Map<String, Object> map = new HashMap<>();
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(map, headers);
        String queryPath = config.getDockerHost() + "/v1/monitor/list";
        ResponseEntity<String> responseEntity = restTemplate.exchange(queryPath, HttpMethod.GET, request, String.class);
        JSONObject jsonObject = new JSONObject();
        FormData formData = jsonObject.parseObject(responseEntity.getBody(), FormData.class);
        return formData;
    }
    public Integer getNum(String courseId,Long chapterId,Long userId){
       return containerToImagesRepository.countByCourseIdAndChapterIdAndUserIdAndIsAuto(courseId,chapterId,userId,false);
    }

    public ResponseEntity<byte[]> downloadFile(String ipAddr,String port ,String dir, String fileName){
        return ioUtils.downLoadFile(ipAddr,port,dir,fileName);
    }
    public ResponseEntity<Map> uploadFile(String ipAddr,String port , String dir, String fileName, byte[] data){

        return ioUtils.uploadFile(ipAddr, port, dir, fileName, data);
    }

    public void deleteAllByCourseId(String courseId){
        containerToImagesRepository.deleteByCourseId(courseId);
        chapterImagesRepository.deleteByCourseId(courseId);
    }
}